<script lang="ts" setup>
import { ElTree, FormInstance, FormRules } from 'element-plus'
import { TreeNodeData } from 'element-plus/es/components/tree/src/tree.type'
import { Menu, getMenuListApi } from '/@/api/auth/menu'
import { addRoleApi, updateRoleApi } from '/@/api/auth/role'
import { CreateEditDialog, EditDialogType } from '/@/components/QsEditDialog'
import { baseMessage } from '/@/utils/message'

const menuList = ref<Menu[]>([])
const getMenuList = async () => {
  const { result } = await getMenuListApi()
  menuList.value = result
}

const formRef = ref<FormInstance>()
const updateId = ref<number>()
const emit = defineEmits(['refresh'])
const form = ref<Partial<defs.common.RoleCreateBody>>({
  name: '',
  introduction: '',
  menu: [],
  isDefault: false,
  isEnabled: true,
})
const confirm = async (type: EditDialogType) => {
  await formRef.value?.validate().then(async () => {
    const menus = [...(treeRef.value?.getCheckedKeys() || []), ...(treeRef.value?.getHalfCheckedKeys() || [])] as string[]
    form.value.menu = menus
    if (type == EditDialogType.ADD) {
      const { result } = await addRoleApi(form.value)
      if (result) {
        baseMessage('添加成功')
      }
    } else {
      if (!updateId.value) return
      const { result } = await updateRoleApi(updateId.value, form.value)
      if (result) {
        baseMessage('修改成功')
      }
    }
  })
}

const treeRef = ref<InstanceType<typeof ElTree>>()
const filterText = ref('')
watch(filterText, (val) => {
  treeRef.value!.filter(val)
})
const filterNode = (value: string, data: TreeNodeData) => {
  if (!value) return true
  return data.meta.title?.includes(value) ?? false
}

const filterChecked = (data: string[]) => {
  const menuListIdMap = new Map<string, string[]>()
  const filterMenuListIds = (menuList: Menu[]) => {
    menuList.forEach((item) => {
      menuListIdMap.set(String(item.id), item.children?.map((item) => String(item.id)) ?? [])
      if (item.children) {
        filterMenuListIds(item.children)
      }
    })
  }
  filterMenuListIds(menuList.value)
  const newChecked = new Set<string>()
  data.forEach((item) => {
    if (menuListIdMap.has(item) && menuListIdMap.get(item)?.every((item) => newChecked.has(item))) {
      newChecked.add(item)
    }
  })
  return [...newChecked]
}

interface Role extends Omit<defs.common.Role, 'menus'> {
  menus?: Menu[]
}
const { open, show, Dialog } = new CreateEditDialog<Role>({
  title: '角色',
  confirm: confirm,
  closeCallback: () => {
    formRef.value?.resetFields()
    form.value.menu = []
  },
  openCallBack: ({ data, type }) => {
    if (data) {
      if (type == EditDialogType.EDIT) {
        updateId.value = data.id
        nextTick(() => {
          const menus = filterChecked(data.menus?.map((item: Menu) => String(item.id)) ?? [])
          treeRef.value?.setCheckedKeys(menus)
          delete data.menus
        })
        form.value = data
      }
    }
  },
  refresh: () => emit('refresh'),
})
export type ShowEditDialog = typeof open

const rules: FormRules = {
  name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
  introduction: [{ required: true, message: '请输入角色描述', trigger: 'blur' }],
}
defineExpose({
  open,
})

onBeforeMount(() => {
  getMenuList()
})
</script>

<template>
  <Dialog>
    <el-form ref="formRef" label-width="80px" :model="form" :rules="rules">
      <el-form-item label="角色名称" prop="name">
        <el-input v-model="form.name" />
      </el-form-item>
      <el-form-item label="角色描述" prop="introduction">
        <el-input v-model="form.introduction" />
      </el-form-item>
      <el-form-item label="是否默认" prop="isDefault">
        <el-switch v-model="form.isDefault" />
      </el-form-item>
      <el-form-item label="是否启用" prop="isEnabled">
        <el-switch v-model="form.isEnabled" />
      </el-form-item>
      <el-form-item label="菜单">
        <el-input v-model="filterText" class="mb-10px" clearable placeholder="输入关键字进行过滤" />
        <div class="vab-tree-border w-full">
          <el-tree
            v-if="show"
            ref="treeRef"
            :check-strictly="false"
            :data="menuList"
            :filter-node-method="filterNode"
            node-key="id"
            show-checkbox
          >
            <template #default="{ data }">
              <span>{{ data.meta.title }}</span>
            </template>
          </el-tree>
        </div>
      </el-form-item>
    </el-form>
  </Dialog>
</template>

<style lang="scss" scoped>
.vab-tree-border {
  width: 100%;
  height: 300px;
  padding: var(--el-padding);
  overflow-y: auto;
  border: 1px solid var(--el-border-color);
  border-radius: var(--el-border-radius-base);
}
</style>
